package com.qding.park.common.core.aspect;

import java.lang.reflect.Method;

import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import com.qding.park.common.core.annotation.EFFECT_POSITION_ENUM;
import com.qding.park.common.core.annotation.MethodCachEvict;
import com.qding.park.common.core.annotation.MethodCacheable;
import com.qding.park.common.core.annotation.STORAGE_LOCATION_ENUM;
import com.qding.park.common.core.aspect.context.CacheEvictContext;
import com.qding.park.common.core.aspect.context.CacheableContext;
import com.qding.park.common.core.exceptions.ExceptionMessage;
import com.qding.park.common.core.exceptions.frame.cache.FrameCacheException;
import com.qding.park.common.core.redis.JedisClient;

/**
 * @ClassName ExpContextHelper
 * @Description TODO(spring 表达式构造 帮助类)
 * @author Administrator
 * @Date 2016年10月15日 下午9:25:03
 * @version 1.0.0
 */
public class ExpContextHelper {

	public static String cache_key_constant="sys_cache_value";
	
	public static CacheableContext createCacheContext(MethodCacheable cacheable, ProceedingJoinPoint pjpoint,
			JedisClient jedisClient) throws FrameCacheException {

		CacheableContext context = new CacheableContext();

		Object targetObj = pjpoint.getTarget();
		Method method = getMethod(pjpoint);
		Class<?> returnType = method.getReturnType();
		// 表达式
		ExpressionParser parser = new SpelExpressionParser();
		EvaluationContext exvContext = structExpContext(method, pjpoint.getArgs());

		// key
		String keyEl = cacheable.key();
		// 过期时间
		String expireEl = cacheable.expire();
		// hash key
		String hashkeyEl = cacheable.hashKey();

		if (StringUtils.isBlank(keyEl)) {
			throw new FrameCacheException(FrameCacheException.TypeEnum.EXCEPTION_ANNOTATION_NOSET.getId(), null,
					ExceptionMessage.createExceptionMessage(
							FrameCacheException.TypeEnum.EXCEPTION_ANNOTATION_NOSET.getDesc(), "缺失key属性",
							"MethodCacheable缺失key属性"));
		}

		String key = (String) parser.parseExpression(keyEl).getValue(exvContext, targetObj);
		int expire = StringUtils.isBlank(expireEl) ? -1
				: parser.parseExpression(expireEl).getValue(exvContext, targetObj, int.class);
		String hashkey = StringUtils.isBlank(hashkeyEl) ? ""
				: parser.parseExpression(hashkeyEl).getValue(exvContext, targetObj,String.class);
		
		STORAGE_LOCATION_ENUM location=cacheable.storageLocation();
		String cache_value="";
		if(location==STORAGE_LOCATION_ENUM.HASH){
			if(StringUtils.isBlank(hashkey)){
				throw new FrameCacheException(FrameCacheException.TypeEnum.EXCEPTION_ANNOTATION_NOSET.getId(), null,
						ExceptionMessage.createExceptionMessage(
								FrameCacheException.TypeEnum.EXCEPTION_ANNOTATION_NOSET.getDesc(), "缺失hashkey属性",
								"MethodCacheable缺失hashkey属性"));
			}
			cache_value=jedisClient.hget(key, hashkey);
		}else{
			cache_value=jedisClient.get(key);
		}
		
//		if(StringUtils.isBlank(cache_value)||"null".equals(cache_value)){
//			cache_value="";
//		}
		
		exvContext.setVariable(cache_key_constant, cache_value);
		context.setCache_value(cache_value);
		context.setKey(key);
		context.setHashKey(hashkey);
		context.setEvaluationContext(exvContext);
		context.setReturnType(returnType);
		context.setExpire(expire);
		context.setLocation(location);
		return context;
	}
	
	
	
	public static CacheEvictContext createCacheContext(MethodCachEvict cachEvict, ProceedingJoinPoint pjpoint) throws FrameCacheException {
		
		CacheEvictContext  cacheEvictContext=new CacheEvictContext();
		String keyEl =cachEvict.key();
		if (StringUtils.isBlank(keyEl)) {
			throw new FrameCacheException(FrameCacheException.TypeEnum.EXCEPTION_ANNOTATION_NOSET.getId(), null,
					ExceptionMessage.createExceptionMessage(
							FrameCacheException.TypeEnum.EXCEPTION_ANNOTATION_NOSET.getDesc(), "缺失key属性",
							"MethodCacheable缺失key属性"));
		}
		
		Method method = getMethod(pjpoint);
		Object targetObj = pjpoint.getTarget();
		ExpressionParser parser = new SpelExpressionParser();
		EvaluationContext exvContext = structExpContext(method, pjpoint.getArgs());
		String key = (String) parser.parseExpression(keyEl).getValue(exvContext, targetObj);
		cacheEvictContext.setKey(key);
		
		String hashkeyEl = cachEvict.hashKey();
		String hashkey = StringUtils.isBlank(hashkeyEl) ? ""
				: parser.parseExpression(hashkeyEl).getValue(exvContext, targetObj,String.class);
		STORAGE_LOCATION_ENUM location=cachEvict.storageLocation();
		if(location==STORAGE_LOCATION_ENUM.HASH&&StringUtils.isBlank(hashkey)){
			throw new FrameCacheException(FrameCacheException.TypeEnum.EXCEPTION_ANNOTATION_NOSET.getId(), null,
					ExceptionMessage.createExceptionMessage(
							FrameCacheException.TypeEnum.EXCEPTION_ANNOTATION_NOSET.getDesc(), "缺失hashkey属性",
							"MethodCacheable缺失hashkey属性"));
		}
		cacheEvictContext.setHashKey(hashkey);
		cacheEvictContext.setLocation(location);
		
		EFFECT_POSITION_ENUM  position=cachEvict.position();
		return null;
	}

	private static Method getMethod(ProceedingJoinPoint pjp) {
		MethodSignature signature = (MethodSignature) pjp.getSignature();
		Method method = signature.getMethod();

		return method;

	}

	/**
	 * @Description (构建el表达式上下文)
	 */
	private static EvaluationContext structExpContext(Method method, Object[] args) {
		LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
		String[] paraNameArr = u.getParameterNames(method);
		StandardEvaluationContext context = new StandardEvaluationContext();
		for (int i = 0; i < paraNameArr.length; i++) {
			context.setVariable(paraNameArr[i], args[i]);
		}

		return context;

	}
}
